PhysCraft, читал, там очень мало написано, и совсем не то что я ожидал. В принципе я вроде смог прописать путь по папкам, сделал что бы играла музыка, в игре модели видно, но в редакторе нет, и как я теперь буду в редакторе ландить? Мне импорт для ландшафта нужен. Есть какой-то способ в редакторе тоже видеть?
Гммм... В первый раз о подобном слышу. Как "лечить" я не знаю, но как вариант можно скачать нужную версию игры и взять нужный архив вместо повреждённого оттуда. Примерно таким образом я избавился от проблем со своей версией, связанных с отсутствием музыки и стандартных реплик, а также отказом воспринимать большУю часть импортированных звуков.
Если по игроку то массив переменных по игроку, если прям каждого конкретного героя каждого игрока - то через custom value или прочий регистратор юнитов.
WakVellios, можно импортировать свой звук, прописав ему путь такой же, как у одного из стандартных. Но при этом тот самый заменённый (стандартный) звук будет недоступен, пока импортированный звук не удалить.
Я знаю что это координаты умник.. пустые придирки не прокатят
я не только про координаты, я про всё
короче судя по всему ты пытаешься написать прогу которая бы думала вместо тебя
и это очень пичально
поэтому я просто оставлю это здесь
int GetPrice (unit whichUnit)
{
int i = GetPlayerTechCount( GetOwningPlayer( whichUnit ), techId, true )
int a=225
loop {exitwhen(i<=0); a=a+(i+1)*225; i=i-1}
return a
}
Странное понимание механики. Не бывает универсального лучшего способа, потому и существуют разные способы для конкретных ситуаций.
А экономить байты и такты процессора, заранее пользуясь интерпретируемым скриптовым языком, это вообще моветон.
Разве массив в WarCraft III не предынициализирует 8192 ячейки памяти (по Вашей формуле, в моём случае он потребляет 8192*4=32768 байт, то есть 32Кб)? Он ведь не динамический.
Нет, он динамический. Исходный размер при создании - 1024. И расширяется на 1024 ячейки по мере доступа вплоть до максимальных 8192.
Оба файла удаляются, потому что ты импортируешь их в карту через программу и не добавляешь данные о файлах в файл импорта(war3map.imp). При сохранении карты в редакторе архив пересобирается, и в него добавляются сторонние файлы, которые сохранены в том самом файле импорта. Поэтому используй стандартный менеджер импорта в редакторе.
Объясню, почему я удалил код: после проведённого за кодом времени, я понял, что сильно погорячился, задав такой глупый вопрос. Стоило отдохнуть, проветрить голову, и решение нашлось. Тем, кто столкнулся с хоть самую малость, но похожей проблемой, дам совет: всегда проверяйте соответствия заклинаний, написанных в коде jass (CTRL + D, если кто не знает, как узнать id заклинания) и ,конечно, сам синтаксис. Также посоветую не утраивать "свалку" в коде, как это сделал я. В общем, если кому интересно, как я решил проблему, пишите - расскажу или даже помогу если у вас она схожая.(Всё дело во внимательности)...
Сброшу код триггера таким, каким я его хотел видеть изначально:
function MU_Check_lvl_four takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('A011', udg_Akame_Killer) == 4 ) ) then
return false
endif
return true
endfunction
function MU_Check_lvl_three takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('A011', udg_Akame_Killer) == 3 ) ) then
return false
endif
return true
endfunction
function MU_Check_lvl_two takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('A011', udg_Akame_Killer) == 2 ) ) then
return false
endif
return true
endfunction
function MU_Check_lvl_one takes nothing returns boolean
if ( not ( GetUnitAbilityLevelSwapped('A011', udg_Akame_Killer) == 1 ) ) then
return false
endif
return true
endfunction
function MU_Second_Conditions takes nothing returns boolean
if ( not ( UnitHasBuffBJ(GetEventDamageSource(), 'B008') == true ) ) then
return false
endif
if ( not ( GetEventDamageSource() == udg_Akame_Killer ) ) then
return false
endif
return true
endfunction
function MU_Start_Conditions takes nothing returns boolean
if ( not ( UnitHasBuffBJ(GetAttacker(), 'B008') == true ) ) then
return false
endif
if ( not ( GetAttacker() == udg_Akame_Killer ) ) then
return false
endif
return true
endfunction
function Trig_MU_Conditions takes nothing returns boolean
if ( not MU_Start_Conditions() ) then
return false
endif
return true
endfunction
function MU_Venum_Check takes nothing returns boolean
if ( not ( udg_MU_Venum_counter == 2 ) ) then
return false
endif
return true
endfunction
function MU_del takes nothing returns nothing
if ( MU_Check_lvl_one() ) then
call SetPlayerAbilityAvailableBJ( true, 'A00X', GetOwningPlayer(GetEventDamageSource()) )
call UnitRemoveAbilityBJ( 'A00X', GetEventDamageSource() )
else
if ( MU_Check_lvl_two() ) then
call SetPlayerAbilityAvailableBJ( true, 'A00U', GetOwningPlayer(GetEventDamageSource()) )
call UnitRemoveAbilityBJ( 'A00U', GetEventDamageSource() )
else
if ( MU_Check_lvl_three() ) then
call SetPlayerAbilityAvailableBJ( true, 'A00Y', GetOwningPlayer(GetEventDamageSource()) )
call UnitRemoveAbilityBJ( 'A00Y', GetEventDamageSource() )
else
if ( MU_Check_lvl_four() ) then
call SetPlayerAbilityAvailableBJ( true, 'A013', GetOwningPlayer(GetEventDamageSource()) )
call UnitRemoveAbilityBJ( 'A013', GetEventDamageSource() )
else
call DoNothing( )
endif
endif
endif
endif
endfunction
function Trig_MU_Actions takes nothing returns nothing
call DestroyTrigger(udg_MU_trig)
set udg_MU_Venum_counter = GetRandomInt(1, 5)
set udg_MU_TG = GetAttackedUnitBJ()
if ( MU_Venum_Check() ) then
if ( MU_Check_lvl_one() ) then
call UnitAddAbilityBJ( 'A00X', udg_Akame_Killer )
call SetPlayerAbilityAvailableBJ( false, 'A00X', GetOwningPlayer(udg_Akame_Killer) )
else
if ( MU_Check_lvl_two() ) then
call UnitAddAbilityBJ( 'A00U', udg_Akame_Killer )
call SetPlayerAbilityAvailableBJ( false, 'A00U', GetOwningPlayer(udg_Akame_Killer) )
else
if ( MU_Check_lvl_three() ) then
call UnitAddAbilityBJ( 'A00Y', udg_Akame_Killer )
call SetPlayerAbilityAvailableBJ( false, 'A00Y', GetOwningPlayer(udg_Akame_Killer) )
else
if ( MU_Check_lvl_four() ) then
call UnitAddAbilityBJ( 'A013', udg_Akame_Killer )
call SetPlayerAbilityAvailableBJ( false, 'A013', GetOwningPlayer(udg_Akame_Killer) )
else
call DoNothing( )
endif
endif
endif
endif
set udg_MU_trig = CreateTrigger()
call TriggerRegisterUnitEvent( udg_MU_trig, udg_MU_TG, EVENT_UNIT_DAMAGED )
call TriggerAddCondition( udg_MU_trig, Condition( function MU_Second_Conditions ) )
call TriggerAddAction( udg_MU_trig, function MU_del )
else
call DoNothing( )
endif
endfunction
//===========================================================================
function InitTrig_MU takes nothing returns nothing
set gg_trg_MU = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_MU, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_MU, Condition( function Trig_MU_Conditions ) )
call TriggerAddAction( gg_trg_MU, function Trig_MU_Actions )
endfunction
Суть триггера:
Имеется способность с четырьмя уровнями. На каждом уровне урон способности разный, а шанс срабатывания всегда 25%. При атаке герой, имеющий такую способность имеет шанс (25%) на отравление противника.
Переменная udg_Akame_killer равносильна GetEventDamageSource()
P.S. Возможно кому-то даже пригодится этот код... Сделан полнейшим неумехой в плане jass, так что не судите строго!
nvc123,
у меня подобным образом сделаны почти все спелы моей карте и всё ок. Если бы ты сделал карты, в которые хоть кто-то играет, то тебя можно было бы ещё слушать, а так. В доте тоже вон всё на хэше и триггерах и всё ок. Ещё и cjass предлагаешь.
Все, разобрался. Тема закрыта)))~ssbbssc, Не нельзя, просто сама модель очень маленькая а при увеличении ее в игре баф над головой и под моделькой (например аура) становится очень огромным, а модель вроде нормальная
Поставить таймер на 10 минут и забрать способность. Пример: Заклинание, которое даёт юниту способность на определённое время.
scope SwordCharge initializer Init
{
private int SCharge = 'A000'//Id of used ability
private real SCT = 20.//Time
private int SCB = 'A001' Given ability
private void SCTimer()
{
timer t = GetExpiredTimer()
int id = GetHandleId(t)
unit u = LoadUnitHandle(H, GetHandleId(t), 0)
UnitRemoveAbility(u, SCB)
PauseTimer(t)
DestroyTimer(t)
u = null
t = null
}
private void Actions()
{
timer t = CreateTimer()
unit u = GetSpellAbilityUnit()
SaveUnitHandle(H, GetHandleId(t), 0, u)
UnitAddAbility(u, SCB)
TimerStart(t, SCT, false, function SCTimer)
t = null
u = null
}
void Init(){
trigger SwordChargeTrg = new trigger;
TriggerRegisterAnyUnitEventBJ(SwordChargeTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerAddCondition(SwordChargeTrg, Condition(function Conditions))
TriggerAddAction( SwordChargeTrg, function Actions)
}
}
Засовываем змеиную ловкость в спелбук, а спелбук блокируем командой "Игрок - Enable/Disable Ability". В скрытый спелбук можно добавлять только пассиные способности. Ищи на тему как скрыть способность, иконку/кнопку способности. xgm.guru/forum/showthread.php?t=31722 И называйте норм тему
Нужна особая анимация, смотри внимательно анимации гулей и мясников, там вроде spell channel, у волков нету такой анимации, так что либо кастом проигрывай анимацию атаки либо делай свою модель волка с нужными анимациями, на основе стандартной.
Воу... Джаз не обязательно изучать, всё это можно сделать и на ГУИ, тем более такую простую способность. На этом сайте есть тема "Заклинания на заказ". Заказывай, жди, получай, изучай. Если прям горит, могу сделать для тебя сам.
поискал и не нашел ничего похожего.
есть предложение связать прогресс постройки с текущим % хп здания или с кастомной переменной типа real, тоже для %
или с тем же кастом велью, собсно
плюс если у тебя есть юнит индексер - все становится еще проще
хендл - это целое число в хэш таблице варика(ид объекта)
хэндл в данном случае это номер ячейки памяти
хэштейблы тут вообще не причём
в варике реализовано нечто наподобие сборки мусора для хэндллов
если хэндл используется(занесён в переменную) то память не помечается как свободная
по коду
используй таймеры вместо триггеров
лучше использовать стек вместо хэштейбла
Не boolean а booexpr - это фильтр для группы, там никакие локалка не нужны.
Саму группу можно перебирать в цикле что правда дает шанс попасть в лимит операций и грохнуть поток.
Делать нужно примерно вот так :
function OnlyEnemyGroundAlive takes nothing returns boolean
return GetUnitState( GetFilterUnit(), UNIT_STATE_LIFE )> 0.405 and IsUnitEnemy( GetFilterUnit(), bj_groupEnumOwningPlayer ) and IsUnitType( GetFilterUnit(), UNIT_TYPE_GROUND )
endfunction
function DamageEnemy takes nothing returns nothing
call UnitDamageTarget( bj_lastReplacedUnit, GetEnumUnit(), 100.00, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
endfunction
function Temp takes nothing returns nothing
local group grp = CreateGroup( ) //создаём группу юнитов
local real dx = 0.00 // координата x
local real dy = 0.00 // координата y
set bj_groupEnumOwningPlayer == Player(0) // глобальная переменная чтобы передать данные в фильтр
call GroupEnumUnitsInRange( grp, dx, dy, 512.00, Condition( function OnlyEnemyGroundAlive) )
set bj_lastReplacedUnit = GetTriggerUnit( )// глобальная переменная чтобы передать данные в другую функцию.
call ForGroup( grp, function DamageEnemy )
call DestroyGroup( grp )
set grp = null
endfunction
У тебя логическая ошибка в цикле. На первом витке, если группа пустая, то i увеличиться на 400! На следующем еще на 400. В итоге, ты при выходе получаешь индекс 400*400+1. Но я не уверен, что до этого дойдет. При 819*, не помню макс размер массива,у тебя просто накроется все. В общем, у тебя логическая ошибка
И, да, ласткриейтедюнит можно занести в локальную переменную, т.к.лайс* - глобалка из common типа unit
не надо удалять war3imported\ надо правильно прописывать путь текстур, у каждой модели есть файлик ридми, и в нем написано по какому пути должны лежать текстуры напритмер ты импортнул модель и текстуру и у тебя получился путь war3imported\ 1.blp а в ридми написано textures\1.blp или просто 1.BLP правишь путь именно так как написано.
а если вдруг нету файлика ридми то модель всегда можно открыть блокном ----> поиск текста "blp" и тебе подстветиться среди символов строка как надо прописать текстуры
Там и защиты то никакой нету, деоптимизатором прошёлся да и все, код редактируешь одтельно и вставляешь в уже подготовленную карту.
Вот опен карта, там все изи...
они реализованы не через векторы, а через события с малым периодом времени
Для начала определись с терминами, у тебя получается, что периодическое событие заменяет векторы. Любое движение, это переодическое событие, векторы только удобный способ их записи.
на сколько я понял снаряд является юнитом
тогда надо к юниту-снаряду атачить структуру-снаряд (через хеш/хендл/юзердата)
делаешь проверку у юнита цели на наличие рядом юнита-снаряда
если юнит-снаряд есть то берёшь приатаченный к нему экземпляр структуры-снаряда и меняешь в нём значение полей
короткий пример атача через юзердату
Missile a=Missile.new(); // создаёт снаряд и юнита для него
a.ms=200; // устанавливаем скорость на 200
SetUnitUserData(a.myUnit, a); // сохраняем в юзердату юнита a.myUnit экземпляр структуры a
...
...
Missile a=GetUnitUserData(u); // извлекаем экземпляр структуры из юзердаты юнита u
a.ms=100; // устанавливаем скорость на 100
подробнее есть в статьях xgm.guru/p/wc3/articles
читай всё что связано с ооп/атачи/хеш-таблицы
Нашёл решение для тебя.
Пол-ночи провозился, но нашёл. почему-то это стало делом чести - открыть сию карту в редакторе
В общем, берёшь архив из аттача и тупо суёшь папку UI в корень варкрафта. После этого карта будет открываться любым вариантом редактора - как JNGP (любым), так и (даже!) стандартным.
Важно: локальные файлы должны быть разрешены.
Только там такой срач и дичь, что лучше реально своими руками с нуля писать...
Добавь способность в книгу заклинаний(спелбук, находиться где-то в способностях для предметов) и заблокируй этот спелбук игроку, чьи юниты должны иметь ту способность(запретить способность надо триггерно, функция запрета скила можешь найти где то в пункте ''игрок''), потом просто добавь книгу заклинаний юниту, когда тот в области. Таким образом, пассивка будет работать, но при этом её иконки не будет видно.
Карта с нестандартными молниями и описанием. Смотреть Readme в менеджере импорта.
Если тебе типа фиолетовой молнии рубика надо, то вот есть вроде этого
так как там нет геометрии (а только источники частиц), то так просто в один клик не рассчитываются границы
надо вручную создавать объект "форма" с нужным радиусом и координатами, в редакторе узлов model editor'а
Всё равно большинство игроков формирует отряды по ролям: стрелки в одну группу, рукопашные в другую и т. д. Поэтому я голосую за первый вариант. А чтобы было удобнее, можно добавить функцию "выбрать всех" или что-то в этом духе.
а) Создай 2 переменные-массива по типу "боевая единица" (массив - чтобы для каждого игрока, мы ведь за мультиплеер трем, прально?), назови типа MyChampion и MyChampionDummy.
б) подготовь невидимого героя-пустышку с нужной тебе иконкой, убери ману, если у чемпиона ее нет. Убери ему радиус обзора, убери галочки типа "отмечать на мини-карте" - остальные - опционально.
В дальнейшем мы будем синхронизировать пустышку и реального чемпиона, создавая видимость одной боевой единицы.
Итак, наш первый триггер:
в) Отследи первое появление чемпиона, когда это случится - создай для игрока героя-пустышку. Соответственно сделай MyChampion [number of (Owner of trained unit)]= last trained unit, следующей строчкой создай того самого героя-пустышку для (owner of trained unit) и сделай MyChampionDummy = last created unit. Теперь мы прочно связали этих чуваков. Этот же триггер запускает остальные.
г) Отслеживание здоровья. Сделай изначально выключенный цикличный триггер, там, каждые 0.3 секунды. Триггер запускается пунктом в). Каждые 0.3 секунды меняй здоровье героя (чья икона висит, надо чтобы она соответствовала, прально?) в % на здоровье самого чемпиона.
д) пропищи событие, мол, если выбирает игрок своего героя (кликая на иконку) выбирается чемпион
е) убивай героя вместе с чемпионом
ж) отключай триггеры с проверкой и выбором, пока чемпион мертв
з) не забывай обновлять переменную чемпиона с каждым новым чемпионом.
ClotPh, делаем все спелы без ограничения ренджа
когда кастуем спелл проверяем расстояние до цели и кастуем спелл либо если слишком далеко то приказываем двигаться к цели каста
потом проверяем таймером расстояние до цели и отдаём приказ каст если расстояние подходит
если отдан любой приказ за исключением "движение в точку" то прекращаем проверку
должен сразу предупредить что делать за тебя никто не будет
теперь по твоим вопросам
чтобы нельзя было кликать скрываешь, даёшь москиты, делаешь видимым
действие проиграть звук и указываешь твою фразу
выбираем всех подходящих(враги,живые) юнитов в радиусе от точки каста и создаём по дамми юниту(юнит без модели, без атаки, с москитами, с нужной способность, время жизни юнита 1 сек) для каждого подходящего юнита приказывая дамми юниту применить нужную способность в подходящего юнита
таким образом каждый дамми юнит применит нужную способность (в твоём случае корни) в 1 подходящего юнита для которого он и был создан а потом исчезнет
Emerald Gem, тут нужна система снарядов
создаёшь свои собственный снаряды на основе юнитов
триггерно двигаешь их
триггерно проверяешь попадание в цель
короче скачай готовую систему снарядов(их дофига на этом сайте а в гугле вообще 100500) и модифицируй её
либо прочти статьи про триггерное движение и сделай свою
если ты не знаешь джасс а учить не собираешься то можешь сделать осадной тип атаки своим юнитам
он тогда будет бить по точке а не по юниту (можно будет увернуться от снаряда просто отойдя в сторону)
В РО, такое невозможно сделать. Подробно на триггерах? Ну вот пример, а если нужно ещё подробнее, то учебник по Jass в руки.
На проклятие в РО,или любой другой спелл,ставится минимальная дистанция
function Trig_Spell_Actions takes nothing returns nothing
local location loc = Location(GetWidgetX(GetSpellAbilityUnit()),GetWidgetY(GetSpellAbilityUnit()))
local unit u = null
if GetSpellAbilityId() == 'АЙ ДИ СКИЛЛА' then
set u = CreateUnitAtLoc(GetOwningPlayer(GetSpellAbilityUnit()),'АЙ ДИ ДАММИ ЮНИТА-ЭФФЕКТА',loc,0.00)
call IssueTargetOrder(u,"curse",GetSpellTargetUnit())
endif
call RemoveLocation(loc)
set loc = null
endfunction
//===========================================================================
function InitTrig_Spell takes nothing returns nothing
local integer i = 0
set gg_trg_Spell = CreateTrigger()
loop
exitwhen i > 12
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set i = i + 1
endloop
call TriggerAddAction( gg_trg_Spell , function Trig_Spell_Actions )
endfunction
Потом тоже самое, только отследить каст проклятия, проверить тип юнита и удалить его из игры.
» WarCraft 3 / Музыка с папкой
» WarCraft 3 / Молнии с помощью триггеров
» WarCraft 3 / Тип оружия - Нет
» WarCraft 3 / Звуки Юнитов
» WarCraft 3 / Как написать код на Jass
» WarCraft 3 / Сбивается импорт ИИ в карту
» WarCraft 3 / Ошибка при проверке кода
» WarCraft 3 / Анимация модели
» WarCraft 3 / Помогите со способностью
» WarCraft 3 / Выбор боевой единицы
» WarCraft 3 / Поворот
» WarCraft 3 / 'ANcl'
» WarCraft 3 / Ошибка в коде
» WarCraft 3 / Пишет не удается открыть модель mdl
» WarCraft 3 / атака мили и рендж
» WarCraft 3 / Редактирование способностей в Jass
» WarCraft 3 / Движение снарядов
» WarCraft 3 / триггерный уворот
» WarCraft 3 / эффекты
» WarCraft 3 / Не работает триггер на мультиплеер
» WarCraft 3 / Текст поверх интерфейса
» WarCraft 3 / Ограничение для героев
» WarCraft 3 / Триггерные снаряды